/*************************************************************************
 * Copyright 2008 David Almilli
 *  
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *  
 *     http://www.apache.org/licenses/LICENSE-2.0 
 *      
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License.
 **************************************************************************/
package com.tivo.hme.bananas;

import static com.tivo.hme.bananas.IBananasPlus.*;

public class BHighlightsPlus extends BHighlights {
    
    private int barRight;
    private int barLeft;
    private int barFlags;
    private boolean arrowInside;

	public BHighlightsPlus(IHighlightsLayout layout) {
		super(layout);
	}

    /**
     * Set a whispering arrow. The arrow will be placed at the given
     * coordinates and will use the given action.
     *
     * This is a thread-safe public entry point.
     * 
     * @param name one of H_UP, H_DOWN, H_LEFT, H_RIGHT
     * @param anchorX one of the A_XXXX constants, plus an optional delta
     * @param anchorY one of the A_XXXX constants, plus an optional delta
     * @param action the action to fire when that key is pressed
     */
	@Override
    public void setWhisperingArrow(String name, int anchorX, int anchorY, Object action) {
    	setWhisperingArrow(name, anchorX, anchorY, action, 0);
    }


    /**
     * Set a whispering arrow. The arrow will be placed at the given
     * coordinates and will use the given action.
     *
     * This is a thread-safe public entry point.
     * 
     * @param name one of H_UP, H_DOWN, H_LEFT, H_RIGHT
     * @param anchorX one of the A_XXXX constants, plus an optional delta
     * @param anchorY one of the A_XXXX constants, plus an optional delta
     * @param action the action to fire when that key is pressed
     */
    public void setWhisperingArrow(String name, int anchorX, int anchorY, Object action, int flags) {
        BPoint p = getBApp().getSkin().getAnchor(name, getRect(), anchorX, anchorY);
		BHighlight h = createHighlight(name, action, p.x, p.y, flags);
		applyVisibility(h, flags, H_VIS_FOCUS);
        set(h);
    }
    
    /**
     * Set a pageup/down hint. The hint will be placed at the given coordinates.
     *
     * This is a thread-safe public entry point.
     * 
     * @param name one of H_PAGEUP, H_PAGEDOWN
     * @param anchorX one of the A_XXXX constants, plus an optional delta
     * @param anchorY one of the A_XXXX constants, plus an optional delta
     */
    @Override
    public void setPageHint(String name, int anchorX, int anchorY) {
    	setPageHint(name, anchorX, anchorY, 0);
    }

    /**
     * Set a pageup/down hint. The hint will be placed at the given coordinates.
     *
     * This is a thread-safe public entry point.
     * 
     * @param name one of H_PAGEUP, H_PAGEDOWN
     * @param anchorX one of the A_XXXX constants, plus an optional delta
     * @param anchorY one of the A_XXXX constants, plus an optional delta
     */
    public void setPageHint(String name, int anchorX, int anchorY, int flags) {
        BPoint p = getBApp().getSkin().getAnchor(name, getRect(), anchorX, anchorY);

		BHighlight h = createHighlight(name, null, p.x, p.y, flags);
		applyVisibility(h, flags, H_VIS_TRUE);
        set(h);
    }
    
    protected void applyVisibility(BHighlight h, int flags, int defaultValue) {
    	if ((flags & FLAG_VIS_FALSE) == FLAG_VIS_FALSE) {
    		h.setVisible(H_VIS_FALSE);
    		
    	} else if ((flags & FLAG_VIS_TRUE) == FLAG_VIS_TRUE) {
    		h.setVisible(H_VIS_TRUE);
    		
    	} else if ((flags & FLAG_VIS_FOCUS) == FLAG_VIS_FOCUS) {
    		h.setVisible(H_VIS_FOCUS);
    	} else {
    		h.setVisible(defaultValue);
    	}
    }
	
    /**
     * Set a bar.
     *
     * This is a thread-safe public entry point.
     *
     * @param dx x offset, relative to 0,0 on the view
     * @param width bar width
     */
    @Override
    public void setBar(int dx, int width) {
    	setBar(dx, width, FLAG_DEFAULT);
    }

    public void setBar(int dx, int width, int flags) {
		BSkin.Element e = getBApp().getSkin().get(H_BAR);
		int y = (getRect().height - e.getHeight()) / 2;

		BHighlight h = createHighlight(e.getName(), null, dx, y, flags);
		h.setAbove(false);
		h.setStretchWidth(width);
		applyVisibility(h, flags, H_VIS_FOCUS);
		set(h);
	}
    
    /**
     * Create a highlight with the given info
     * @param name the name of the highlight
     * @param action the action for the highlight
     * @param x the x location of the highlight
     * @param y the y location of the highlight
     * @param flags the flags associated with the highlight
     * @return the new highlight instance
     */
    protected BHighlight createHighlight(String name, Object action, int x, int y, int flags) {
		BHighlight h;
		if ((flags & FLAG_DISABLED) != 0) {
			h = new BDisabledHighlight(name, action, x, y);
		} else {
			h = new BHighlightPlus(name, action, x, y);
		}
		return h;
    }
    
    public int getVisibilityForFlags(int flags, int defaultValue) {
        if ((flags & FLAG_DISABLED) == FLAG_DISABLED) {
        	if ((flags & FLAG_DISABLED_NOFOCUS) == FLAG_DISABLED_NOFOCUS) {
            	return H_VIS_FOCUS;
            } else {
            	return H_VIS_FALSE;
            }
        } else {
        	return defaultValue;
        }
    }

    /**
	 * Set the background bar and (optional) whispering left/right arrows.
	 * 
	 * This is a thread-safe public entry point.
	 * 
	 * @param bar_left
	 *            If BAR_HANG, the bar extends off the side of the screen. If
	 *            BAR_DEFAULT, the bar touches the edge of the button. Otherwise
	 *            this is an offset from 0.
	 * @param bar_right
	 *            If BAR_HANG, the bar extends off the side of the screen. If
	 *            BAR_DEFAULT, the bar touches the edge of the button. If
	 *            negative, this is an offset from the right edge. If positive
	 *            this is an offset from the left edge.
	 * @param action_left
	 *            if not null, the button will contain a whispering left arrow
	 *            that fires this action.
	 * @param action_right
	 *            if not null, the button will contain a whispering right arrow
	 *            that fires this action.
	 * @param inside
	 *            if true, the arrows will be placed inside the button.
	 *            Otherwise they will be placed outside.
	 */
    @Override
    public void setBarAndArrows(int bar_left, int bar_right,
                                Object action_left, Object action_right,
                                boolean inside) {
    	setBarAndArrows(bar_left, bar_right, FLAG_DEFAULT, FLAG_DEFAULT,
                action_left, action_right, inside);
    }

    public void setBarAndArrows(int bar_left, int bar_right, int bar_flags, int arrow_flags,
                                Object action_left, Object action_right,
                                boolean inside) {
    	setBarAndArrows(bar_left, bar_right, bar_flags, arrow_flags,
                action_left, action_right, inside, true);
    }

    public void setBarAndArrows(int bar_left, int bar_right, int bar_flags, int arrow_flags,
                                Object action_left, Object action_right,
                                boolean inside, boolean createBar) {
        //
        // bar_left
        // |
        // |      whi_left
        // | padh  |
        // 
        //   ============================
        //  ==        
        // ==     /
        // ==     \
        //  ==     
        //   ============================
        // 
        //
        this.barRight = bar_right;
        this.barLeft = bar_left;
        this.barFlags = bar_flags;
        this.arrowInside = inside;

        BApplication app = getBApp();
        BScreen screen = getLayout().getScreen();
        BRect rect = getRect();

        BSkin.Element e = app.getSkin().get(H_BAR);
        BSkin.Element left = app.getSkin().get(H_LEFT);
        BSkin.Element right = app.getSkin().get(H_RIGHT);
        int cap = e.getInt(P_CAP, 30);
        int padh = e.getInt(P_PAD_H, 10);
        int w = app.getSkin().get(H_LEFT).getWidth();
        if ((w & 1) == 1) {
            ++w;
        }

        int originx = -rect.x;
        int safeTitleH = ((BApplicationPlus)screen.getBApp()).getSafeTitleHorizontal();

        //
        // left
        //

        int whi_left;
        switch (bar_left) {
          case BAR_HANG:
            bar_left = originx - cap;
            whi_left = originx + safeTitleH - left.getWidth();
            break;
          default:
            whi_left = bar_left + (inside ? padh : -w);
            break;
        }
    
        //
        // right
        //
        
        int whi_right;
        switch (bar_right) {
          case BAR_HANG:
            bar_right = screen.getWidth() + originx;
            whi_right = bar_right - safeTitleH - w + right.getWidth();
            bar_right += cap;
            break;
          default:
            if (bar_right <= 0) {
                bar_right += rect.width;
            }
            whi_right = bar_right;
            if (inside) {
                whi_right -= padh + w;
            }
            break;
        }

        //
        // now set the highlights
        //
        if (createBar) {
        	//the bar should be created
            setBar(bar_left, bar_right - bar_left, bar_flags);
    	}
        if (action_left != null) {
            setWhisperingArrow(H_LEFT,  A_LEFT + whi_left, 0, action_left, arrow_flags);
        } else {
            remove(H_LEFT);
        }
        if (action_right != null) {
            setWhisperingArrow(H_RIGHT, A_LEFT + whi_right, 0, action_right, arrow_flags);
        } else {
            remove(H_RIGHT);
        }
    }

    public int getBarLeft() {
        return barLeft;
    }

    public int getBarRight() {
        return barRight;
    }

    public int getBarFlags() {
        return barFlags;
    }

    public boolean isArrowInside() {
        return arrowInside;
    }

}
